package com.rainwen.shiro.configuration;

import com.rainwen.shiro.filter.UrlPermissionFilter;
import com.rainwen.shiro.security.ChainDefinitionSectionMetaSource;
import com.rainwen.shiro.security.MyCredentialsMatcher;
import com.rainwen.shiro.security.UserRealm;
import com.rainwen.shiro.service.SysUserService;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

/**
 * Shiro配置
 * @author rain.wen
 * @date 2017/8/9
 */
@EnableAutoConfiguration
@Configuration
@ConditionalOnExpression("${shiro.enable:true}")
@EnableConfigurationProperties(ShiroSettings.class)
public class ShiroConfiguration {

    /**
     * @param userService 用户业务对象
     * @param myCredentialsMatcher 凭证匹配器，例如:密码加密
     * @return
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public UserRealm userRealm(SysUserService userService, MyCredentialsMatcher myCredentialsMatcher) {
        UserRealm realm = new UserRealm();
        realm.setUserService(userService);
        realm.setName("userAuthRealm");
        realm.setCredentialsMatcher(myCredentialsMatcher);
        //启用认证缓存，当用户登录一次后将不在查询数据库来获取用户信息，直接在从缓存获取
        realm.setAuthenticationCachingEnabled(true);
        realm.setAuthorizationCachingEnabled(true);
        return realm;
    }

    @Bean(name = "ehcacheManager")
    public EhCacheManager getEhCacheManager() {
        EhCacheManager em = new EhCacheManager();
        em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
        return em;
    }

    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm, EhCacheManager ehcacheManager) {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(userRealm);
        defaultWebSecurityManager.setCacheManager(ehcacheManager);
        return defaultWebSecurityManager;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager defaultWebSecurityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
        return new AuthorizationAttributeSourceAdvisor();
    }

    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(ShiroSettings settings,
                                                            DefaultWebSecurityManager defaultWebSecurityManager,
                                                            ChainDefinitionSectionMetaSource chainDefinitionSectionMetaSource) {

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

        shiroFilterFactoryBean.setLoginUrl(settings.getLoginUrl());
        shiroFilterFactoryBean.setSuccessUrl(settings.getSuccessUrl());
        shiroFilterFactoryBean.setUnauthorizedUrl(settings.getUnauthorizedUrl());

        LogoutFilter logoutFilter = new LogoutFilter();
        logoutFilter.setRedirectUrl(settings.getLogoutUrl());
        shiroFilterFactoryBean.getFilters().put("logout", logoutFilter);

        UrlPermissionFilter urlPermissionFilter = new UrlPermissionFilter();
        shiroFilterFactoryBean.getFilters().put("urlPermission", urlPermissionFilter);

        shiroFilterFactoryBean.setFilterChainDefinitionMap(chainDefinitionSectionMetaSource.getObject());

        return shiroFilterFactoryBean;
    }

    @Bean(name = "myCredentialsMatcher")
    public MyCredentialsMatcher getMyCredentialsMatcher(){
        return new MyCredentialsMatcher();
    }

    @Bean(name = "chainDefinitionSectionMetaSource")
    public ChainDefinitionSectionMetaSource chainDefinitionSectionMetaSource(ShiroSettings settings) {
        ChainDefinitionSectionMetaSource chainDefinitionSectionMetaSource = new ChainDefinitionSectionMetaSource();
        chainDefinitionSectionMetaSource.setFilterChainDefinitions(settings.getFilterChainDefinitions());
        return chainDefinitionSectionMetaSource;
    }

}
